C Programlama Dili ile geliştirdiğimiz bazı uygulamalarda, sağladığı bazı kolaylıklar nedeniyle, Python kodları kullanmak isteyebiliriz.
Bu işlemi gerçekleştirmek için sırasıyla aşağıdaki adımları uygulayalım:
1. İşlemleri uygularken kullanacağımız CodeBlocks IDE ve Python sürümlerini kontrol edelim. Biz her iki programın da 32 bit sürümünü kullanıyoruz. Siz dilediğiniz sürümlerini kulanabilirsiniz, ancak her iki programın da sürümleri aynı (32 veya 64 bit) olmalıdır:
2. CodeBlocks IDE ile python_proj adlı yeni C projesi oluşturalım ve derleyip çalıştıralım:
3. Ana menüden Proje - Build options seçeneğine tıklayarak açılan pencerede,
4. Aşağıdaki ifadenin Windows PATH değişkeni içinde tanımlı olduğunu kontrol edelim.
C:\Program Files (x86)\CodeBlocks\MinGW\bin
5. libpython312.a dosyasını oluşturmak için aşağıdaki adımları sırasıyla uygulayalım:
gendef.exe ve dlltool.exe dosyaları aşağıdaki dizinde bulunan ve MinGW uygulamasına ait dosyalardır.
C:\Program Files (x86)\CodeBlocks\MinGW\bin
6. main.c dosyasını aşağıdaki şekilde düzenleyin:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
int main(int argc, char *argv[])
{
PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pValue;
// To prevent "Could not find platform independent libraries <prefix>" warning message
// Setting PYTHONHOME and PYTHONPATH environment variables
_putenv("PYTHONHOME=C:\\Python3.12.3_32");
_putenv("PYTHONPATH=C:\\Python3.12.3_32\\Lib;C:\\Python3.12.3_32\\DLLs");
// Initialize the Python interpreter.
// In an application embedding Python, this should be called before using any other Python/C API functions
Py_Initialize();
// Adding Python packages path to system path variable to use packages like "requests" installed in Python.
// Return the object name from the sys module or NULL if it does not exist, without setting an exception.
PyObject *sysPath = PySys_GetObject("path");
// Append the object item at the end of list list.
// Return 0 if successful; return -1 and set an exception if unsuccessful.
PyList_Append(sysPath, PyUnicode_FromString("C:\\Python3.12.3_32\\lib\\site-packages\\"));
// Print path variable
// PyObject* str_unicode = PyObject_Repr(sysPath); // Get unicode object
// PyObject* pyStr = PyUnicode_AsEncodedString(str_unicode, "utf-8", "Error ~");
// const char *sys_path = PyBytes_AS_STRING(pyStr);
// printf("%s\n", sys_path);
// Python code file that must be in the same directory with .exe file
// Decode a null-terminated string from the filesystem encoding and error handler.
pName = PyUnicode_DecodeFSDefault("python_code_file"); // python_code_file.py
// Import Python code file to a PyObject object
pModule = PyImport_Import(pName);
// Release a strong reference to object pName, indicating the reference is no longer used.
Py_DECREF(pName);
if(pModule != NULL) {
// Get Python function to a PyObject object
pFunc = PyObject_GetAttrString(pModule, "python_function");
// PyCallable_Check() function determines if an object is callable. Return 1 if the object is callable and 0 otherwise.
if(pFunc && PyCallable_Check(pFunc)) {
// PyObject_CallObject(pFunc, NULL); // Calling Python function with no parameter an return value
// Set parameters of the Python function
// Creates a new tuple object of size 3
pArgs = PyTuple_New(3);
// Create a Unicode object from a string and assign to a PyObject object
pValue = PyUnicode_FromString("String1");
// Set the first item of tuple to pValue
PyTuple_SetItem(pArgs, 0, pValue);
pValue = PyUnicode_FromString("String2");
// Set the second item of tuple to pValue
PyTuple_SetItem(pArgs, 1, pValue);
// Create a Unicode object from a long value and assign to a PyObject object
pValue = PyLong_FromLong(421);
// Set the third item of tuple to pValue
PyTuple_SetItem(pArgs, 2, pValue);
// Call pFunc Python object with arguments given by the tuple pArgs.
// If no arguments are needed, then args can be NULL.
pValue = PyObject_CallObject(pFunc, pArgs);
// Release a strong reference to object pArgs, indicating the reference is no longer used.
Py_DECREF(pArgs);
if(pValue != NULL) {
printf("Python function return value: %ld\n", PyLong_AsLong(pValue));
Py_DECREF(pValue);
}
else {
Py_DECREF(pFunc);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr, "Function call failed!\n");
return 1;
}
}
else {
if(PyErr_Occurred()) PyErr_Print();
fprintf(stderr, "Cannot find function \"%s\"\n", "python_function");
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load \"%s\"\n", "python_code_file");
return 1;
}
// Undo all initializations made by Py_Initialize()
if(Py_FinalizeEx() < 0) {
return 120;
}
return 0;
}
7. python_code_file.py dosyasını aşağıdaki şekilde düzenleyerek C:\MyCProgs\python_proj\bin\Debug dizinine kopyalayalım:
def python_function(param1, param2, param3):
print("Python function first parameter: " + param1)
print("Python function second parameter: " + param2)
print("Python function third parameter: ", param3)
return param3 * 2
Yukarıdaki fonksiyon, C programı tarafından çağrılan ve ilk ikisi karakter dizisi ve üçüncüsü int olmak üzere toplam üç parametre geçirilen bir Python fonksiyonudur. Fonksiyon tüm parametreleri ekrana yazar ve int parametre değerinin iki katını alarak, elde ettiği değeri geri döndürür.
8. C:\Python3.12.3_32 dizinindeki python312.dll dosyasını C:\MyCProgs\python_proj\bin\Debug dizinine kopyalayalım.
9. Sonuç olarak, C:\MyCProgs\python_proj\bin\Debug dizini altında aşağıdaki 3 dosya yer almalıdır:
Programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:
Python function first parameter: String1 Python function second parameter: String2 Python function third parameter: 421 Python function return value: 842
1. Python/C API'lerini kullanmak için gereken tüm fonksiyon, tip ve makro tanımları aşağıdaki satırlar ile koda dahil edilir.
#define PY_SSIZE_T_CLEAN
#include <Python.h>
Python.h başlık dosyasını koda dahil etmek, Python uzantı modülleri oluşturma, Python yorumlayıcısını bir C/C++ programına yerleştirme veya Python işlevlerini C/C++ kodundan çağırma gibi Python'u diğer uygulamalara yerleştirirken genellikle gereklidir.
2. 5 adet PyObject nesnesi oluşturulur.
PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pValue;
3. "Could not find platform independent libraries <prefix>" uyarı mesajını önlemek için, _putenv() fonksiyonu ile PYTHONHOME ve PYTHONPATH adlı iki adet ortam değişkeni oluşturularak, Python3.12.3 programının ana dizin, Lib ve DLLs dizinleri yol tanımlamaları eklenir.
_putenv("PYTHONHOME=C:\\Python3.12.3_32");
_putenv("PYTHONPATH=C:\\Python3.12.3_32\\Lib;C:\\Python3.12.3_32\\DLLs");
4. Py_Initialize() fonksiyonu ile, Python yorumlayıcısı başlatılır. Bu fonksiyon, Python kullanan bir uygulamada, herhangi bir Python/C API fonksiyonunu kullanmadan önce çağrılmalıdır.
5. PySys_GetObject() fonksiyonu ile, "path" değişken değeri alınarak sysPath nesnesine atanır.
6. PyList_Append() fonksiyonu ile, Python paketlerinin kurulu olduğu dizin sysPath nesnesine eklenir. Böylece, Python'da kurulu "requests" gibi paketleri C'de kullanabiliriz.
7. PyUnicode_DecodeFSDefault() fonksiyonu ile, "python_code_file" karakter dizisi pName nesnesine atanır.
8. PyImport_Import() fonksiyonu ile, pName nesnesi yoluyla "python_code_file.py" dosyası okunarak pModule nesnesine atanır.
9. PyObject_GetAttrString() fonksiyonu ile "python_function" fonksiyonu pFunc nesnesine atanır.
10. PyCallable_Check() fonksiyonu pFunc nesnesinin çağrılabilir olup olmadığı kontrol edilir.
11. PyTuple_New() fonksiyonu ile, fonksiyona geçirilecek olan parametreler için 3 elemanlı bir tuple oluşturulur.
12. PyUnicode_FromString() fonksiyonu ile iki karakter dizisi ve PyLong_FromLong() fonksiyonu ile int bir değer oluşturularak, PyTuple_SetItem() fonksiyonu ile tuple elemanlarına aktarılır.
13. PyObject_CallObject() fonksiyonu ile Python fonksiyonu çağrılır.
14. Python fonksiyonu tüm parametreleri ekrana yazar ve int parametre değerinin iki katını alarak, elde ettiği değeri geri döndürür.